# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import enum
from typing import List

from coin.exchange.huobi_futures.kr_rest.constants import (
    contract_type_list,
    contract_base_list,
)
from coin.exchange.huobi.kr_rest.native_private_client import (
    HuobiSyncQueryer,
    HuobiAsyncQueryer,
)
from coin.exchange.okex_futures.types import (OkexFuturesOrderSide as HuobiFuturesOrderSide)

HuobiFuturesOrderSide = HuobiFuturesOrderSide

HUOBI_FUTURES_API_HOST = 'api.hbdm.com'


class HuobiFuturesOrderPriceType(enum.Enum):
  LIMIT = 'limit'
  OPPONENT = 'opponent'
  POST_ONLY = 'post_only'


class HuobiFuturesOffsetType(enum.Enum):
  OPEN = "open"
  CLOSE = "close"


class HuobiFuturesDirectionType(enum.Enum):
  BUY = "buy"
  SELL = "sell"


class HuobiFuturesStatusType(enum.IntEnum):
  READY_TO_SUBMIT = 1
  ORDERED = 2
  NEW = 3
  PARTIAL_FILLED = 4
  PARTIAL_CANCELED = 5
  FULLY_FILLED = 6
  CANCELED = 7
  CANCELING = 11


class HuobiFuturesNativePrivateClient(object):
  def __init__(self,
               *,
               key_file,
               api_host=None,
               disable_ssl=False,
               timeout=10,
               max_connections=8,
               use_async=False,
               rest_lib='pycurl'):
    rest_lib = rest_lib or None
    api_host = api_host or HUOBI_FUTURES_API_HOST
    if use_async:
      self._auth_queryer = HuobiAsyncQueryer(key_file,
                                             api_host=api_host,
                                             disable_ssl=disable_ssl,
                                             timeout=timeout,
                                             max_connections=max_connections,
                                             rest_lib=rest_lib)
    else:
      self._auth_queryer = HuobiSyncQueryer(key_file, api_host=api_host, timeout=timeout)

  def _query(self, method, path, params=None):
    return self._auth_queryer.query(method, path, params=params)

  def query_fills(self, symbol):
    method = 'POST'
    url = '/api/v1/contract_matchresults'
    params = {
        "symbol": symbol,
        "trade_type": 0,
        "create_date": 1,
    }
    update = self._query(method, url, params)
    return update

  def query_account_info(self, symbol=None):
    method = 'POST'
    url = '/api/v1/contract_account_info'
    params = {
        "symbol": symbol,
    }
    update = self._query(method, url, params)
    return update

  def query_position_info(self, symbol=None):
    method = 'POST'
    url = '/api/v1/contract_position_info'
    params = {
        "symbol": symbol,
    }
    update = self._query(method, url, params)
    return update

  def query_order_info(
      self,
      symbol,
      order_id_list: List[str],
  ):
    method = 'POST'
    url = '/api/v1/contract_order_info'
    assert len(order_id_list) <= 50, len(order_id_list)
    params = {
        "symbol": symbol,
        "order_id": ','.join(order_id_list),
    }
    update = self._query(method, url, params)
    return update

  def query_order_detail(self,
                         symbol,
                         order_id,
                         created_at,
                         order_type,
                         page_index=None,
                         page_size=None):
    method = 'POST'
    url = '/api/v1/contract_order_detail'
    params = {
        "symbol": symbol,
        "order_id": order_id,
        "created_at": created_at,
        "page_index": page_index,
        "order_type": order_type,
        "page_size": page_size,
    }
    update = self._query(method, url, params)
    return update

  def query_open_orders(
      self,
      symbol,
      page_index=None,
      page_size=50,
  ):
    method = 'POST'
    url = '/api/v1/contract_openorders'
    assert symbol in contract_base_list, symbol
    params = {
        'symbol': symbol,
        'page_index': page_index,
        'page_size': page_size,
    }
    update = self._query(method, url, params)
    return update

  def query_historical_orders(
      self,
      symbol,
      trade_type,
      order_status_type,
      order_status,
      create_date,
      page_index=None,
      page_size=None,
  ):
    method = 'POST'
    url = '/api/v1/contract_hisorders'
    assert 1 <= page_size <= 50, page_size
    params = {
        'symbol': symbol,
        'trade_type': trade_type,
        'type': order_status_type,
        'status': order_status,
        'create_date': create_date,
        'page_index': page_index,
        'page_size': page_size,
    }
    update = self._query(method, url, params)
    return update

  def place_order(
      self,
      *,
      symbol=None,
      contract_type=None,
      contract_code=None,
      client_order_id=None,
      price,
      volume,
      direction: HuobiFuturesDirectionType,
      offset: HuobiFuturesOffsetType,
      leverage_rate,
      order_price_type: HuobiFuturesOrderPriceType,
  ):
    method = 'POST'
    url = '/api/v1/contract_order'
    if contract_code is None:
      assert symbol in contract_base_list and contract_type in contract_type_list
    else:
      assert symbol is None and contract_type is None

    params = {
        'symbol': symbol,
        'contract_type': contract_type,
        'contract_code': contract_code,
        'client_order_id': client_order_id,
        'price': price,
        'volume': volume,
        'direction': direction.value,
        'offset': offset.value,
        'lever_rate': leverage_rate,
        'order_price_type': order_price_type.value,
    }
    update = self._query(method, url, params)
    return update

  def batch_place_order(self, params):
    method = 'POST'
    url = '/api/v1/contract_batchorder'
    # TODO check params
    update = self._query(method, url, params)
    return update

  def cancel_order(self, *, symbol, order_id=None, client_order_id=None):
    method = 'POST'
    url = '/api/v1/contract_cancel'
    assert bool(order_id) != bool(client_order_id), (order_id, client_order_id)
    params = {
        "symbol": symbol,
        "order_id": order_id,
        "client_order_id": client_order_id,
    }
    update = self._query(method, url, params)
    return update

  def cancel_all_orders(self, symbol):
    method = 'POST'
    url = '/api/v1/contract_cancelall'
    params = {
        'symbol': symbol,
    }
    update = self._query(method, url, params)
    return update
